package com.come4loves.game.module.fight.model;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.atomic.AtomicInteger;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.come4loves.core.utils.RandomUtils;
import com.come4loves.game.dataconfig.model.EquipCardConfig;
import com.come4loves.game.dataconfig.model.GeneralCardConfig;
import com.come4loves.game.dataconfig.service.EquipCardService;
import com.come4loves.game.dataconfig.service.GeneralCardService;
import com.come4loves.game.module.card.constant.CardType;
import com.come4loves.game.module.fight.action.BatchAction;
import com.come4loves.game.module.fight.action.BuffAction;
import com.come4loves.game.module.fight.action.CardToLocationAction;
import com.come4loves.game.module.fight.action.MagicChangeAction;
import com.come4loves.game.module.fight.action.MomentAction;
import com.come4loves.game.module.fight.constants.BuffType;
import com.come4loves.game.module.fight.constants.CardLocation;
import com.come4loves.game.module.fight.constants.FightConst;
import com.come4loves.game.module.fight.constants.FightMoment;
import com.come4loves.game.module.fight.constants.SkillMoment;
import com.come4loves.game.module.fight.constants.Team;
import com.come4loves.game.module.fight.helper.ActionRecorder;
import com.come4loves.game.module.fight.helper.BuffHelper;
import com.come4loves.game.module.skill.helper.SkillHelper;
import com.come4loves.game.module.skill.helper.TargetHelper;

public class ActorBattle {
	
	protected Logger LOGGER = LoggerFactory.getLogger(this.getClass());
	/**
	 * 角色id
	 */
	private long actorId;
	/**
	 * 当前法力值
	 */
	private int currentMagic;
	/**
	 * 最大法力值
	 */
	private int maxMagic;
	
	/**
	 * 桌面卡牌
	 */
	private DeskOfCard<FightCard> deskOfCard;
	
	/**
	 * 主角区域
	 */
	private List<MainCardArea> mainCardAreas;
	
	/**
	 * 队伍
	 */
	private Team team;
	/**
	 * 已使用的牌
	 */
	private Map<Integer,FightCard> usedCards = new LinkedHashMap<Integer, FightCard>() ;
	/**
	 * 出下去的卡牌
	 */
	private Map<Integer,FightCard> showCards = new LinkedHashMap<Integer, FightCard>() ;
	/**
	 * 手牌
	 */
	private Map<Integer,FightCard> handCards = new LinkedHashMap<Integer, FightCard>() ;
	private Map<Integer,FightCard> exposeCards = new LinkedHashMap<Integer, FightCard>() ;
	
	/**
	 * 已使用完的牌
	 */
	private List<FightCard> garbageCards = new ArrayList<FightCard>();
	
	/**
	 * 时机
	 */
	private FightMoment fightMoment = FightMoment.GET_CARD;
	
	/**
	 * 当前出牌目标
	 */
	private Map<FightCard, List<FightCard>> currentTarget = new HashMap<>();
	
	private AtomicInteger idCreater;
	
	private boolean isAi = false;;
	
	public ActorBattle(long actorId, int currentMagic, int maxMagic, DeskOfCard<FightCard> deskOfCard, List<MainCardArea> mainCardAreas, Team team, AtomicInteger idCreater, boolean ai) {
		super();
		if (ai) {
			this.actorId = -1;
		} else {
			this.actorId = actorId;
		}
		this.currentMagic = currentMagic;
		this.maxMagic = maxMagic;
		this.deskOfCard = deskOfCard;
		this.mainCardAreas = mainCardAreas;
		this.team = team;
		this.isAi = ai;
		initCardsId(idCreater);
		
		this.deskOfCard.shuffleCard();
	}
	
	public void initCardsId(AtomicInteger idCreater) {
		this.idCreater = idCreater;
		for (MainCardArea mainCardArea : mainCardAreas) {
			mainCardArea.getMainCard().setId(idCreater.getAndIncrement());
		}
		
		for (FightCard fightCard : deskOfCard.getCards()) {
			fightCard.setId(idCreater.getAndIncrement());
		}
	}
	
	public List<FightCard> getAllCards(){
		List<FightCard> list = new ArrayList<FightCard>();
		list.addAll(this.handCards.values());
		list.addAll(this.usedCards.values());
		list.addAll(this.showCards.values());
		list.addAll(this.exposeCards.values());
		list.addAll(this.garbageCards);
		for (MainCardArea mainCardArea : mainCardAreas) {
			list.addAll(mainCardArea.allCards());
		}
		list.addAll(this.deskOfCard.remainCards());
		return list;
		
	}
	/**
	 * 增加当前法力值
	 * @param value
	 */
	public void increaseCurrentMagic(int value) {
		this.currentMagic += value;
	}
	/**
	 * 增加最大法力值
	 * @param value
	 */
	public void increaseMaxMagic(int value) {
		this.maxMagic += value;
	}
	/**
	 * 扣除当前法力值
	 * @param value
	 */
	public void deductCurrentMagic(int value) {
		if (this.currentMagic <= value) {
			this.currentMagic = 0;
		} else {
			this.currentMagic -= value;
		}
		
	}
	/**
	 * 回满法力值
	 */
	public void fullMagic(ActionRecorder actionRecorder){
		this.maxMagic += FightConst.EACH_ROUND_ADD_MAGIC;
		this.currentMagic = this.maxMagic;
		MagicChangeAction magicChangeAction = new MagicChangeAction(this.getActorId(), this.getCurrentMagic(), this.getMaxMagic());
		actionRecorder.addAction(magicChangeAction);
	}
	/**
	 * 自动出牌
	 * @return
	 */
	public List<FightCard> autoShowCard(ActionRecorder actionRecorder, Collection<ActorBattle> allActorBattles){
		Collection<FightCard> list = this.usedCards.values();
		List<FightCard> result = new ArrayList<FightCard>();
		for (FightCard fightCard : list) {
			if (fightCard.getCardType().equals(CardType.UNIT)) {
				actionRecorder.addLocation(fightCard,  CardLocation.STATCK);
				
				summonUnit(actionRecorder, fightCard, allActorBattles);
			} else if (fightCard.getCardType().equals(CardType.SPELL)) {
				this.garbageCards.add(fightCard);
				actionRecorder.addLocation(fightCard,  CardLocation.STATCK);
				actionRecorder.addLocation(fightCard,  CardLocation.DISCARD);
				SkillHelper.handlerSkillModel(fightCard, SkillMoment.RECRUITPHASE, actionRecorder, this, allActorBattles,this.currentTarget.get(fightCard));
			} else if (fightCard.getCardType().equals(CardType.EQUIP)){
				actionRecorder.addLocation(fightCard,  CardLocation.STATCK);
				FightCard mainCard = this.currentTarget.get(fightCard).get(0);
				if (mainCard == null) {
					LOGGER.error("equip cart chooose target error,cardInfo:{}", fightCard.simpleInfo());
					continue;
				}
				MainCardArea mainCardArea = getMainCardArea(mainCard);
				
				if (mainCardArea == null) {
					LOGGER.error("equip cart chooose target error,cardInfo:{}", fightCard.simpleInfo());
					continue;
				}
				EquipCardConfig cfg = EquipCardService.get(fightCard.getCfgId());
				if (cfg.getType() == 1){
					if (mainCardArea.getWeaponCard() != null) {
						actionRecorder.addLocation(mainCardArea.getWeaponCard(),  CardLocation.DISCARD);
						BuffData bd = mainCard.removeBuff(mainCardArea.getWeaponCard().getId());
						actionRecorder.addAction(new BuffAction(mainCard, bd, 0));
					}
					mainCardArea.setWeaponCard(fightCard);
					actionRecorder.addLocation(fightCard,  CardLocation.WEAPON, mainCard.getId());
				} else if (cfg.getType() == 2) {
					if (mainCardArea.getDefCard() != null) {
						actionRecorder.addLocation(mainCardArea.getDefCard(),  CardLocation.DISCARD);
						BuffData bd = mainCard.removeBuff(mainCardArea.getDefCard().getId());
						actionRecorder.addAction(new BuffAction(mainCard, bd, 0));
					}
					mainCardArea.setDefCard(fightCard);
					actionRecorder.addLocation(fightCard,  CardLocation.DEFFENDS, mainCard.getId());
				} else {
					if (mainCardArea.getItemCard() != null) {
						actionRecorder.addLocation(mainCardArea.getItemCard(),  CardLocation.DISCARD);
					}
					mainCardArea.setItemCard(fightCard);
					actionRecorder.addLocation(fightCard,  CardLocation.ITEM, mainCard.getId());
				}
				SkillHelper.handlerSkillModel(fightCard, SkillMoment.EQUIPSUMMONED, actionRecorder, this, allActorBattles,this.currentTarget.get(fightCard));
			}
		}
		this.usedCards.clear();
		return result;
	}
	/**
	 * 召唤生物进场
	 * @param actionRecorder
	 * @param card
	 * @param allActorBattles
	 * @return
	 */
	public List<FightCard> summonUnit(ActionRecorder actionRecorder, FightCard card, Collection<ActorBattle> allActorBattles) {
		List<FightCard> result = new ArrayList<FightCard>();
		if (card.getCardType().equals(CardType.UNIT)) {
			CardToLocationAction locationAction = CardToLocationAction.createFromCard(card, CardLocation.BATTLE, this.actorId);
			actionRecorder.addAction(locationAction);
			showCards.put(card.getId(), card);
			
			BuffData buffData = new BuffData(0, BuffType.SLEEP, 0, 1);
			card.addBuff(buffData);
			BuffAction buffAction = new BuffAction(card,buffData,1);
			actionRecorder.addAction(buffAction);
			SkillHelper.handlerSkillModel(card, SkillMoment.UNITSUMMONED, actionRecorder, this, allActorBattles,this.currentTarget.get(card));
		}
		return result;
	}
	/**
	 * 自动用牌
	 * @param actionRecorder
	 * @return
	 */
	public List<FightCard> autoUseCard(ActionRecorder actionRecorder,Collection<ActorBattle> allActorBattles){
		List<FightCard> list = new ArrayList<FightCard>();
		list.addAll(this.handCards.values());
		Collections.sort(list, new InitValueComparator());
		List<FightCard> result = new ArrayList<FightCard>();
		for (FightCard fightCard : list) {
			if (this.maxMagic == 0) break;
			if (this.currentMagic >= fightCard.getMagic()) {
				
				if (fightCard.getAiTargets().isEmpty()) {
					result.add(fightCard);
					useCard(fightCard.getId(), null,actionRecorder, allActorBattles);
					continue;
				} else {
					
					List<FightCard> targets = TargetHelper.getTargets(fightCard, fightCard.getAiTargets(), this, allActorBattles);
					List<FightCard> randomTargets = new ArrayList<FightCard>();
					if (!targets.isEmpty()){
						List<FightCard> tempTargets = targets;
						if (fightCard.getCardType().equals(CardType.EQUIP)) {//专属装备处理
							EquipCardConfig equipCardConfig = EquipCardService.get(fightCard.getCfgId());
							if (equipCardConfig.getUnitlink() > 0) {
								tempTargets = new ArrayList<FightCard>();
								for (FightCard targetCard : targets) {
									if (targetCard.getCardType().equals(CardType.GENERAL)){
										GeneralCardConfig generalCardConfig = GeneralCardService.get(targetCard.getCfgId());
										if (generalCardConfig.getTid() == equipCardConfig.getUnitlink()) {
											tempTargets.add(fightCard);
										}
									}
								}
							}
						}
						randomTargets.add(tempTargets.get(RandomUtils.nextIntIndex(randomTargets.size())));
						if (randomTargets.isEmpty()) {
							LOGGER.error("auto use card target error! cardInfo:{}", fightCard.simpleInfo());
							continue;
						}
					} else {
						continue;
					}
					result.add(fightCard);
					useCard(fightCard.getId(), randomTargets,actionRecorder, allActorBattles);
				}
				
				
				
				
				
				
			}
		}
		return result;
	}
	
	
	
	public long getActorId() {
		return actorId;
	}
	public int getCurrentMagic() {
		return currentMagic;
	}
	public int getMaxMagic() {
		return maxMagic;
	}
	public DeskOfCard<FightCard> getDeskOfCard() {
		return deskOfCard;
	}
	public List<FightCard> getMainCards() {
		List<FightCard> list = new ArrayList<FightCard>();
		for (MainCardArea mainCardArea : mainCardAreas) {
			list.add(mainCardArea.getMainCard());
		}
		return list;
		
	}
	public Team getTeam() {
		return team;
	}
	public void setTeam(Team team) {
		this.team = team;
	}
	public Map<Integer, FightCard> getShowCards() {
		return showCards;
	}
	public Map<Integer, FightCard> getHandCards() {
		return handCards;
	}
	
	public List<FightCard> getGarbageCards() {
		return garbageCards;
	}
	
	public FightMoment getFightMoment() {
		return fightMoment;
	}
	public void setFightMoment(FightMoment fightMoment) {
		this.fightMoment = fightMoment;
	}
	
	
	
	/**
	 * 检查牌是否是在手中的牌
	 * @param id
	 * @return
	 */
	public boolean checkCardInHand(int id) {
		if (!handCards.containsKey(id)){
			return false;
		}
		return true;
	}
	public boolean checkCardInExpose(int id) {
		if (!this.exposeCards.containsKey(id)){
			return false;
		}
		return true;
	}
	public boolean checkCardMagic(int id) {
		FightCard card = handCards.get(id);
		int costMagic = card.getMagic();
		if (costMagic > this.currentMagic) {
			return false;
		}
		return true;
	}
	/**
	 * 摸牌
	 * @return
	 */
	public List<FightCard> takeCard(){
		int num = FightConst.INIT_HAND_CARD - this.handCards.size();
		if (deskOfCard.remaining() < num) {
			deskOfCard.shuffleCard(this.garbageCards);
			this.garbageCards.clear();
		}
		List<FightCard> cards = deskOfCard.dealCard(num);
		for (FightCard fightCard : cards) {
			this.handCards.put(fightCard.getId(), fightCard);
		}
		
		
		return cards;
	}
	/**
	 * 弃掉手牌
	 * @param num
	 * @return
	 */
	public List<FightCard> dropHandCard(int num) {
		int dropNum = this.handCards.size() > num ? num : this.handCards.size();
		Iterator<Entry<Integer, FightCard>> it = this.handCards.entrySet().iterator();
		List<FightCard> result = new ArrayList<FightCard>();
		int index = 0;
		while (it.hasNext()) {
			if (index >= dropNum) {
				break;
			}
			Entry<Integer, FightCard> entry = it.next();
			it.remove();
			this.garbageCards.add(entry.getValue());
			result.add(entry.getValue());
			index+=1;
		}
		return result;
	}
	public List<FightCard> takeCardToExpose(int num){
		if (deskOfCard.remaining() < num) {
			deskOfCard.shuffleCard(this.garbageCards);
			this.garbageCards.clear();
		}
		List<FightCard> cards = deskOfCard.dealCard(num);
		for (FightCard fightCard : cards) {
			this.exposeCards.put(fightCard.getId(), fightCard);
		}
		
		
		return cards;
	}
	/**
	 * 摸N张牌
	 * @param num
	 * @return
	 */
	public List<FightCard> takeCard(int num){
		if (deskOfCard.remaining() < num) {
			deskOfCard.shuffleCard(this.garbageCards);
			this.garbageCards.clear();
		}
		List<FightCard> cards = deskOfCard.dealCard(num);
		for (FightCard fightCard : cards) {
			this.handCards.put(fightCard.getId(), fightCard);
		}
		
		return cards;
	}
	
	private void addUsedCard(FightCard fightCard){
		this.usedCards.put(fightCard.getId(), fightCard);
	}
	/**
	 * 使用卡牌
	 * @param cardId
	 * @param actionRecorder
	 */
	public void useCard(int cardId, List<FightCard> targetCards, ActionRecorder actionRecorder, Collection<ActorBattle> allActorBattles) {
		FightCard fightCard = handCards.remove(cardId);
		if (targetCards != null && !targetCards.isEmpty()){
			this.currentTarget.put(fightCard, targetCards);
		}
		LOGGER.debug("use card actorId:{}, cardinfo:{}, currentTarget:{}", this.actorId, fightCard.simpleInfo(), targetCards);
		addUsedCard(fightCard);
		this.deductCurrentMagic(fightCard.getMagic());
		MagicChangeAction magicChangeAction = new MagicChangeAction(this.getActorId(), this.getCurrentMagic(), this.getMaxMagic());
		actionRecorder.addAction(magicChangeAction);
		
		if (fightCard.getCardType().equals(CardType.SPELL)) {
			SkillHelper.handlerSkillModel(fightCard, SkillMoment.SPELLCASTED, actionRecorder,this, allActorBattles, this.currentTarget.get(fightCard));
		}
		
	}
	/**
	 * 换牌
	 * @param idList
	 * @param actionRecorder
	 */
	public void changeCard(List<Integer> idList, ActionRecorder actionRecorder, int roundNum) {
		List<FightCard> result = new ArrayList<FightCard>();
		for (int id : idList) {
			FightCard card = this.exposeCards.remove(id);
			result.add(card);
			Card2Location card2Location = new Card2Location(card, CardLocation.LIBRARY);
			CardToLocationAction cardToLocationAction = new CardToLocationAction(card2Location);
			actionRecorder.addAction(cardToLocationAction);
		}
		deskOfCard.add(result, false);
		List<FightCard> takeResult = takeCard(idList.size());
		for (FightCard fightCard : takeResult) {
			this.exposeCards.put(fightCard.getId(), fightCard);
			Card2Location card2Location = new Card2Location(fightCard, CardLocation.EXPOSE);
			CardToLocationAction cardToLocationAction = new CardToLocationAction(card2Location);
			actionRecorder.addAction(cardToLocationAction);
		}
		//展示区牌进入手牌
		for (FightCard fightCard : this.exposeCards.values()) {
			this.handCards.put(fightCard.getId(), fightCard);
			Card2Location card2Location = new Card2Location(fightCard, CardLocation.HAND);
			CardToLocationAction cardToLocationAction = new CardToLocationAction(card2Location);
			actionRecorder.addAction(cardToLocationAction);
		}
		this.setFightMoment(FightMoment.USE_CARD);
		MomentAction momentAction = new MomentAction(actorId, FightMoment.USE_CARD,roundNum);
		actionRecorder.addAction(momentAction);
		
	}
	
	public void tiggerBuff(BatchAction batchAction) {
		List<FightCard> list = new ArrayList<FightCard>();
		for (MainCardArea mainCardArea : mainCardAreas) {
			list.add(mainCardArea.getMainCard());
		}
		
		list.addAll(this.showCards.values());
		for (FightCard fightCard : list) {
			BuffHelper.trigger(fightCard, batchAction);
		}
		
	}
	
	
	public void handleDead() {
		Iterator<Entry<Integer, FightCard>> it = this.showCards.entrySet().iterator();
		while (it.hasNext()) {
			Entry<Integer, FightCard> entry = it.next();
			FightCard fightCard = entry.getValue();
			if (fightCard.isDead()) {
				this.garbageCards.add(fightCard);
				it.remove();
			}
		}
	}
	
	public Map<FightCard, List<FightCard>> getCurrentTarget() {
		return currentTarget;
	}
	public AtomicInteger getIdCreater() {
		return idCreater;
	}
	
	public MainCardArea getMainCardArea(FightCard mainCard) {
		for (MainCardArea area : this.mainCardAreas) {
			if (area.getMainCard().equals(mainCard)){
				return area;
			}
		}
		return null;
	}
	
	public List<MainCardArea> getMainCardAreas() {
		return mainCardAreas;
	}
	
	public boolean isAi() {
		return isAi;
	}
	
	
	
	
}
